<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<script type="text/javascript" src="jquery.js?4"></script>
<script type="text/javascript" src="index.js?4"></script>
<title>DrX -- The Good Doctor</title>
<link rel="stylesheet" href="index.css?4" type="text/css">
</head>

<h1 id="drx">DrX</h1>

<div class="gallery">
<h2 id="gallery">Gallery</h2>
  <a href="314.png"><img width="300" height="255" src="314_thumb.png" title="Examining a float" /></a>
    <br /> <br />
  <a href="datetime.png"><img width="300" height="255" src="datetime_thumb.png" title="Seeing method arguments" /></a>
    <br /> <br />
  <a href="file.png"><img width="300" height="255" src="file_thumb.png" title="Pick the 'crazy' style for randomly mangled, though consistent, shapes." /></a>
    <br /> <br />
  <a href="datamapper.png"><img width="300" height="255" src="datamapper_thumb.png" title="DataMapper" /></a>
    <br /> <br />
  <a href="activerecord.png"><img width="300" height="255" src="activerecord_thumb.png" title="ActiveRecord" /></a>
    <br /> <br />
  <a href="sequel.png"><img width="300" height="255" src="sequel_thumb.png" title="Sequel" /></a>
</div>

<div class="menu">
Links: <a href="http://github.com/mooffie/drx/issues">Bug tracker</a> |
       <a href="http://github.com/mooffie/drx">GitHub page</a> |
       <a href="http://rubygems.org/gems/drx">RubyGems page</a> |
       <span id="toc-button">TOC ⇨</span>
</div>

<p>DrX, the good doctor, is a small <em>object inspector</em> for Ruby.</p>

<p>DrX is for newbies and gurus alike.</p>

<p>Instead of focusing on the <em>contents</em> of your object, DrX
instead focuses on its <em>object model</em>. As a result, DrX
is most suitable for programmers wishing to understand Ruby's object
model better. It's especially adept at showing you how a "magical"
library works (e.g., DataMapper).</p>

<h2 id="features">Key features:</h2>

<ul>
<li>See everything about a Ruby object: its 'klass', 'super',
'iv_tbl', 'm_tbl'. See your singletons with your very own eyes! <br />&nbsp;</li>

<li>Double-click a method to launch an editor
and position the cursor on the exact line where the method is
defined!</li>
</ul>

<h2 id="installation">Installation</h2>

<p>At your system prompt type:</p>

<div><code>gem install drx</code></div>

<h2 id="usage">Usage</h2>

<p>Just <code>require 'drx'</code> in your program and do
<code>some_object.see</code> to investigate that object:</p>

<pre>
require 'rubygems'
require 'drx'

"wizard of oz".see

Math::PI.see

Enumerable.see

s = "wizard of oz"
def s.strong
  "&lt;strong&gt;" + self + "!&lt;/strong&gt;"
end
s.see
</pre>

<p>And see the <a href="#key-bindings">Key bindings</a> section for what you can do in DrX's window.</p>

<h2 id="requirements">Requirements</h2>

<ol>
<li>MRI Ruby 1.8 or 1.9.
  <div class="comment">
    <p>DrX was tested on Ruby 1.8.6 and up. I don't know about earlier versions.</p>
  </div>
  </li>
<li>Ability to compile Ruby C extensions (Because DrX has some part written in C).</li>
<li>The Tk user interface toolkit.
  <div class="comment">
    <p>You can use either the "new" Tk (version 8.5), or the "old" one (version 8.4).</p>
    <p>However, if you use the "old" one, <em>you must also have the Tile extension installed.</em>
    For example, on Ubuntu do <code>sudo apt-get install tk-tile</code>. Alternatively, as a very last
    resort, use an old version of DrX which doesn't necessitates Tile
    (that's any version earlier than 0.4).</p>
    <p>Ubuntu users: <a href="ubuntu-new-tk.html">Here are instructions</a> for compiling your
    Ruby/Tk against the "new" Tk.</a>
  </div>
  </li>
<li>The <a href="http://www.graphviz.org/">GraphViz</a> package (It's used to draw the diagrams).
  <div class="comment">
    <p>If the graphs DrX produces have ragged lines, it means your GraphViz doesn't have
    anti-aliasing support. A quick way to solve this on Ubuntu is by doing
    <code>sudo apt-get install graphviz-cairo</code>.</p>
    <p>Make sure GraphViz' 'bin' folder is in your $PATH.</p>
  </div>
  </li>
</ol>

<p>(A note to MS-Windows users: DrX was installed sucessfully under: RubyInstaller + DevKit; Tk
from ActiveState and bindings via <a href="http://github.com/rdp/tk_as_gem">tk_as_gem</a>.)</p>

<h2 id="recommendations">Recommendations</h2>

<p>DrX <a href="#arguments">can show you the arguments</a> methods expect. While this is not
needed, DrX can work more effectively if you install the "arguments"
and/or the "methodpara" gems. In short, do <code>gem install
rdp-arguments</code> and <code>gem install methopara</code>.</p>

<h2 id="objgraph">The object graph</h2>

<p>The object graph shows the object model. Ruby objects have two "pointers":</p>

<ol>
<li><em>klass</em>, which points to the class of an object.</li>
<li><em>super</em>, which points to the parent of a class.</li>
</ol>

<p>Correspondingly, the object graph shows [at most] two arrows pointing
out of an object: the <em>klass</em> arrow is shown as a dotted arrow,
and is usually pointing to the right (horizontal); and the <em>super</em> arrow is
shown as a solid arrow, and is usually pointing down (vertical).</p>

<p>When you see a horizontal arrow, think of it as "here are the methods
the object responds to"; and when you see a vertical one, think "here are
additional methods".</p>

<p>Eventually you'll recognize that most graphs contain two (vertical)
main lines of inheritance: one for "normal" classes and one for their
corresponding "singleton" classes. This is how Ruby's object model is
designed.</p>

<p class="comment">To prevent clutter, DrX doesn't show you absolutely
all pointers. For example, you'll notice, in the screenshots, that
<em>Kernel</em>'s singleton doesn't point to its super, <em>Module</em>.
It is extremely unlikely that you'll want to see the few components DrX
decides not to show. The fully-documented methods
<code>display_klass?</code> and <code>display_super?</code>, in
<em>lib/drx/graphviz.rb</em>, govern what to show.</p>

<h3 id="colors">Colors and shapes</h3>

<ul>
<li class="color-module">Modules are shown in green</li>
<li class="color-class">Classes are blue ovals. <span class="color-singleton">Singletons are darker, and have "'S" appended to their label.</span></li>
<li class="color-object">Mere objects are brownish houses.</li>
</ul>

<p>(This is true for the default style only.)</p>

<h2 id="variables">The variables table</h2>

<p>A Ruby object has a <em>variables table</em> associated with it. The
variables pane lists the content of this table. It is customary to think
of this table as holding instance <code>@variables</code> <code>@like</code>
<code>@this</code>, but in fact Ruby stores here also constants
("namespaces") and <code>@@class_variables</code>. The pane shows the raw
contents of this table.</p>

<h2 id="methods">The methods table</h2>

<p>A Ruby object, if it's a class or a module, also holds methods. These
are stored in a <em>methods table</em>. The methods pane shows the contents of
this table.</p>

<h2 id="ex1">Example 1: Seeing things</h2>

<p>For our first example, let's suppose you have the following DataMapper code...</p>

<pre>
require 'rubygems'
require 'dm-core'

#
# This is part of a blogging website. Users write posts. A post
# belongs to a user.
#

class Post
  include DataMapper::Resource

  property :post_id,  Serial
  property :title,    String
  property :body,     Text

  belongs_to :user
end

class User
  include DataMapper::Resource

  property :user_uid,  Serial
  property :name,      String
  property :mail,      String
end
</pre>

<p>...and you wish to know what a Post object consists of. You'd append the following code...</p>

<pre>
post = Post.new

require 'drx'
post.see

# Or just do Post.see
</pre>

<p>...and you'd get a window showing you the following graph (click to
enlarge).</p>

<div align="center">
  <a href="datamapper_noshadow.png"><img width="500" height="444"
    src="datamapper_noshadow_thumb.png" title="Screenshot showing DrX in action" /></a>
</div>

<p>In the graph you'll notice two distinct lines of hierarchy. One describes the
Post class: most importantly it contains the
<em>DataMapper::Resource</em> module. The other line describes the Post
class' singleton: most importantly it contains the
<em>DataMapper::Model</em> module. Take a moment to click these two
modules and examine the methods they contain.</p>

<h2 id="ex2">Example 2: Investigating things</h2>

<p>Let's talk more about our Post class. We merely did <code>include
DataMapper::Resource</code> in its body and we see that it's acquired
gazillions of things. We want to know why this had happened.
Specifically, we want to know how DataMapper::Model got there. We
suspect that DataMapper::Resource does this magic in its
<code>#included</code>, and we want to verify this theory.</p>

<p>In other words, we want to peek into DataMapper::Resource's
singleton. Click the "DataMapper::Resource 'S" oval (that's the
singleton) to inspect its methods:</p>

<div align="center">
  <a href="editor.png"><img width="500" height="375"
    src="editor_thumb.png" title="Screenshot showing DrX in action" /></a>
</div>

<p>Aha! We see that it indeed has an <code>included</code> method
defined. Double click on the method to open it up in an editor (as
demonstrated in the screenshot). Yep, our suspicion was correct: the
<em>Model</em> module is added to our Post class by
<code>Resource.included</code>. The mystery is solved!</p>

<h2 id="ex3">Example 3: Sinatra</h2>

<p>Launch DrX's GUI (for example, by doing <code>''.see</code>). At the
eval line type <code>require 'sinatra'</code>. Then type <code>see
Sintra</code>. (Alternatively, type <code>require 'sinatra'</code> at
IRB's prompt and then <code>Sinatra.see</code>.) In the variables table
you'll see all the sub-modules and classes defined under the Sinatra
module. Double-click any of them to investigate it. When you're finished
with one, right-click over the graph to go back.</p>

<p>You can open multiple DrX windows by doing
<code>some_object.see</code> at the eval line. For example, you may do
<code>self.see</code> to duplicate the window. Note, however, that Ruby
seems to have a glitch: doing <code>#instance_eval</code> on an object,
which is what DrX does when you eval something, forces a singleton for
it. You'll see this artefact in the diagram.</p>

<h2 id="ex-c">Example 4: Seeing methods written in C</h2>

<p>If you install the <em>cloc</em> gem, DrX can locate methods
written in C in the same ease it locates pure-Ruby methods. You'll be able to
launch your editor to see the C implementation.</p>

<p>The following example shows the dialog you may carry out with your
shell to setup your system:</p>

<pre>
# Install the cloc gem
$ gem install cloc

# We need to download Ruby's source-code so cloc can index it.
# Let's download it from github.com:
$ git clone http://github.com/rubyspec/matzruby.git

$ cd matzruby

# Let's checkuot the 1.8.7 branch, because this happens to be the
# Ruby we're interested in.
$ git checkout origin/ruby_1_8_7

# Ask cloc to index it:
$ cloc .

# Let's also index the C code in our gems:
$ cd ~/.gem/ruby/1.8
$ cloc .
</pre>

<p>That's all! The next time you launch DrX you'll be able to lanuch your editor and see how
various methods are implemented in C. Here's a screenshot:</p>

<div align="center">
  <a href="cloc.png"><img width="500" height="375"
    src="cloc_thumb.jpg" title="Screenshot showing DrX in action" /></a>
</div>

<h2 id="understanding">Understanding DrX</h2>

<p>Here is how objects are defined internally in MRI ruby (from ruby.h):</p>

<pre>
struct RBasic {
    unsigned long flags;
    VALUE klass;
};

struct RObject {
    struct RBasic basic;
    struct st_table *iv_tbl;
};

struct RClass {
    struct RBasic basic;
    struct st_table *iv_tbl;
    struct st_table *m_tbl;
    VALUE super;
};
</pre>

<p>What DrX does is show you these four slots: the 'klass', the 'super',
the 'iv_tbl', and the 'm_tbl'.</p>

<p class="comment">Additionally, if <code>RBasic::flags</code> has the
<code>FL_SINGLETON</code> bit turned on, DrX will report the class as a
singleton. Note, however, that singletons are just like ordinary
classes, and I'm aware of the fact that painting them differently (in
the object graph) might give a false impression that they are somehow
special.</p>

<h2 id="key-bindings">Key bindings</h2>

<dl>

<dt>The object graph</dt>
<dd>
  <ul>
  <li><span class="gist">Click</span> an object in the graph to <span class="gist">select</span> this object. This updates the variables and methods panes to reflect this object.
      <ul><li>Alternatively, you can select objects by holding down the <span class="gist">control key while moving</span> the mouse. This is useful for quickly skimming through the objects without straining your hands.</li></ul></li>
  <li><span class="gist">Right-click</span> to move <span class="gist">back</span> in history.</li>
  <li><span class="gist">Double-click</span> an object in the graph to make this object the <span class="gist">tip</span> of the graph.
      Why is this useful?
      <ul>
      <li>To set the 'self' for the eval line.</li>
      <li>To see the "real" module behind an included one.</li>
      </ul>
  </li>
  <li><span class="gist">Scrolling</span> is done by:
      <ul>
      <li>The mouse <span class="gist">wheel</span>. (Hold down <span class="gist">shift</span> to scroll sideways.) <span class="comment">This doesn't work in MS-Windows.</span></li>
      <li>Dragging with the <span class="gist">middle</span> mouse button. <em>That's the easiest and fastest way.</em></li>
      </ul>
  </li>
  </ul>
</dd>

<dt>The variables table</dt>
<dd>
  <ul>
  <li><span class="gist">Double-click</span> a variable to "<span class="gist">see</span>" it.</li>
  <li><span class="gist">Click</span> a variable to <span class="gist">pp()</span> it.</li>
  <li><span class="gist">Right-click</span> a variable to <span class="gist">p()</span> it.</li>
  </ul>
</dd>

<dt>The methods table</dt>
<dd>
  <ul>
  <li><span class="gist">Double-click</span> a method to bring up an <span class="gist">editor</span> showing it.</li>
  </ul>
</dd>

<dt>Between the panes</dt>
<dd>
  <ul>
  <li><span class="gist">Click-drag</span> the bars between the panes to <span class="gist">resize</span> the panes.</li>
  </ul>
</dd>

<dt>Eval input line</dt>
<dd>
  <ul>
  <li><span class="gist">Enter</span> to <span class="gist">eval()</span> the code you've typed in the input line.</li>
  <li><span class="gist">Arrow-up</span> and <span class="gist">Arrow-down</span> to move in the input line <span class="gist">history</span>.</li>
  </ul>
</dd>

<dt>Anywhere</dt>
<dd>
  <ul>

  <li><span class="gist">Control-L</span> moves the keyboard focus to the eval <span class="gist">input</span> line.
   (It should be easy to remember this: most web browsers use this key to focus on the address bar.)</li>
  <li><span class="gist">Control-R</span> <span class="gist">refreshes</span> the display. Useful if you eval'ed some code that changes the object inspected.</li>
  </ul>
</dd>

</dl>

<h2 id="editor">Launching an editor</h2>

<p>When you double-click a method, DrX launches the command <code>gedit +%d "%s"</code>
by default (%d and %s are substituted by the line-number
and file-name). If you wish to use some other editor, set your
'DRX_EDITOR_COMMAND' environment variable accordingly (or see the next section).</p>

<p>Note that <em>gedit</em> has a bug: it positions the cursor on the
correct line, but sometimes it doesn't update the display and still shows the
first page of the file. If this happens, click arrow-up, then
arrow-down, to update the display. Or use some other editor.</p>

<p>For Ruby 1.8, DrX figures out a method's location by inspecting
Ruby's internal nodes. This functionality is contained in a small C
extension built when you install the DrX gem. For Ruby 1.9,
<em>Method#source_location</em> is used instead, but, unfortunately, for
Ruby 1.9 attribute readers/setters are reported as <em>&lt;c&gt;</em>
and not as <em>&lt;attr reader&gt;</em> and <em>&lt;attr
setter&gt;</em>. As for methods written in C: locating them is done
by the <em>cloc</em> gem.</p>

<h2 id="drxrc">The ~/.drxrc file</h2>

<p>DrX lets you put your customizations in the file <code>~/.drxrc</code>. Here's an example:</p>

<pre>
class Drx::TkGUI::Application
  def user_customizations
    @eval_result.height = 8          # Enlarge the output area.
    @graph_opts[:size] = '60%'       # Make the graph smaller.
    @graph_opts[:style] = 'crazy'

    # Turn on the "Show arguments" checkbox.
    @show_arguments_chk.variable.value = 1
  end
end

# Use gvim instead of gedit:
Drx::TkGUI::EDITOR_COMMAND.replace('gvim +%d "%s"')
</pre>

<p>As another example, here's a ~/.drxrc snippet for adding a
drop-shadow effect to the object graph.</p>

<pre>
# The following code adds a shadow to the diagram.
#
# It works by tweaking the command DrX usually executes to also execute
# an ImageMagick utility.
#
# !! Don't use this code if you aren't using a fast computer !!

Drx::ObjInfo::GRAPHVIZ_COMMAND.replace '
  dot -Gbgcolor=transparent "{dot}" -Tpng -o "{gif}" -Tcmapx -o "{map}" 2>&1 && \
  convert "{gif}" -matte \\( +clone -background black -shadow 60x4+5+4 \\) \
    +swap -background white -mosaic "{gif}"
'

# If you're on MS-Windows, replace "&&" with ";".

# 2010-Apr-21:
#   The above command will fail for Ruby 1.8.6. That's because Ruby
#   will generate a filename whose extension isn't exactly ".gif",
#   resulting in ImageMagick generating a PNG file, which Tk can't read.
#   I'll try to figure out a solution later. (Ruby 1.8.7 and up are fine.)

# For further explanation, see
# * http://www.imagemagick.org/Usage/thumbnails/#shadow
# * http://www.imagemagick.org/Usage/blur/#shadow
#
# Tip: Decrees the blur (e.g., do "60x2..." instead of "60x4...") if you're
# on a slow computer.
#
</pre>

<h2 id="arguments">Method arguments</h2>

<p>When you check the "Show arguments" checkbox, DrX shows the arguments
the methods expect. DrX uses three different strategies to detect these arguments:</p>

<dl>

<dt>"methopara"</dt>
<dd>On Ruby 1.9.2, or (for earlier 1.9 Rubies) where the "methopara" gem
is installed, there's <code>Mathod#paramaters</code> to tell us about
the arguments.</dd>

<dt>The "arguments" gem</dt>

<dd>(Works on both Ruby 1.8 and 1.9.) If the "arguments" gem is
installed, DrX can use it to detect the arguments. The advantage over
"methopara" is that you can see values of default arguments. Note that
this gem, in turn, uses either ParseTree (for Ruby 1.8) or RubyParser
(for Ruby 1.9), which are relatively slow.</dd>

<dt>arity</dt>
<dd>If none of the above is available, DrX uses the arity of a method to
simulate its arguments. For example, if the arity is 2, the arguments reported
will be "arg, arg"; if the arity is -2, then "arg, *args" will be
reported. This strategy is the fallback in case any of the other ones fail.</dd>

</dl>

<p>Since the "arguments" gem is slow, it's used only if you explicitly
check the "Use the 'arguments' gem" checkbox.</p>

<hr />

<div id="toc">
  <div id="toc-header">Table&nbsp;of&nbsp;Contents</div>
  <div id="toc-links"></div>
</div>

<p>
&nbsp;
</p>
